#define _GNU_SOURCE

#include <stdio.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <err.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/sysinfo.h>
#include <signal.h>
#include <openssl/evp.h>
#include "main.h"

struct abcrypto_instance *a_instance = NULL;
struct abcrypto_instance *b_instance = NULL;
uint16_t test_alg = ABCRYPTO_INVALID_ALG;

uint32_t alen = 0;
uint32_t slen = 256;
uint32_t elen = 256;
uint32_t loop = 1;
uint32_t test_klen = 16;
uint32_t test_skip = 0;
uint32_t test_step = 1;

void print_help(void)
{
	printf("-a  alg     test_alg:\n"
	       "\t\tAES_128_ECB\n"
	       "\t\tAES_128_CBC\n"
	       "\t\tAES_128_CTR\n"
	       "\t\tAES_128_CFB\n"
	       "\t\tAES_128_OFB\n"
	       "\t\tAES_192_ECB\n"
	       "\t\tAES_192_CBC\n"
	       "\t\tAES_192_CTR\n"
	       "\t\tAES_192_CFB\n"
	       "\t\tAES_192_OFB\n"
	       "\t\tAES_256_ECB\n"
	       "\t\tAES_256_CBC\n"
	       "\t\tAES_256_CTR\n"
	       "\t\tAES_256_CFB\n"
	       "\t\tAES_256_OFB\n"
	       "\t\tSM4_ECB\n"
	       "\t\tSM4_CBC\n"
	       "\t\tSM4_CTR\n"
	       "\t\tSM4_CFB\n"
	       "\t\tSM4_OFB\n"
	       "\t\tHASH_MD5\n"
	       "\t\tHASH_SHA1\n"
	       "\t\tHASH_SHA224\n"
	       "\t\tHASH_SHA256\n"
	       "\t\tHASH_SHA384\n"
	       "\t\tHASH_SHA512\n"
	       "\t\tHASH_SHA3_224\n"
	       "\t\tHASH_SHA3_256\n"
	       "\t\tHASH_SHA3_384\n"
	       "\t\tHASH_SHA3_512\n"
	       "\t\tHASH_SM3\n"
	       "\t\tHMAC_MD5\n"
	       "\t\tHMAC_SHA1\n"
	       "\t\tHMAC_SHA224\n"
	       "\t\tHMAC_SHA256\n"
	       "\t\tHMAC_SHA384\n"
	       "\t\tHMAC_SHA512\n"
	       "\t\tHMAC_SHA3_224\n"
	       "\t\tHMAC_SHA3_256\n"
	       "\t\tHMAC_SHA3_384\n"
	       "\t\tHMAC_SHA3_512\n"
	       "\t\tHMAC_SM3\n"
	       "\t\tRANDOM\n");

	printf("-A  <string>       A library name, default openssl.\n");
	printf("-B  <string>       B library name, default mbedtls.\n");
	printf("-s  <slen>     Start of data length range, default 256.\n");
	printf("-e  <elen>     Start of data length range, default 256.\n");
	printf("-d  <alen>        Length of aad before data.\n");
	printf("-l  <loopcount>     Test loop for each length, default 1.\n");
	printf("-k  key length     length of key, default 16.\n");
	printf("-J              Skip when error occurs, count diff count.\n");
	printf("-S  data step   Step in [slen, elen], default 1.\n");
	printf("-h  Show this help.\r\n");
}

int main(int argc, char **argv)
{
	const char *a_string = "openssl";
	const char *b_string = "mbedtls";
	int ch;

	printf("abcrypto Version %s\n", VERSION);
	OpenSSL_add_all_digests();
	while ((ch = getopt(argc, argv, "A:B:ha:s:e:d:l:k:JS:h")) != -1) {
		switch (ch) {
		case 'A':
			a_string = optarg;
			break;
		case 'B':
			b_string = optarg;
			break;
		case 'a':
			if (optarg) {
				test_alg = abcrypto_get_alg(optarg);
			}

			if (test_alg == ABCRYPTO_INVALID_ALG) {
				fprintf(stderr, "Invalid alg %s\n", optarg);
				return -1;
			}
			break;
		case 'S':
			test_step = strtol(optarg, NULL, 10);
			break;
		case 's':
			slen = strtol(optarg, NULL, 10);
			break;
		case 'e':
			elen = strtol(optarg, NULL, 10);
			break;
		case 'd':
			alen = strtol(optarg, NULL, 10);
			break;
		case 'l':
			loop = strtol(optarg, NULL, 10);
			if (loop < 0)
				loop = 1;
			break;
		case 'J':
			test_skip = 1;
			break;

		case 'h':
		default:
			print_help();
			return -1;
		}
	}

	a_instance = abcrytpo_instance_get(a_string);
	b_instance = abcrytpo_instance_get(b_string);
	if (a_instance == NULL || b_instance == NULL) {
		fprintf(stderr, "Not find instance %s or %s\n", a_string,
			b_string);
		return -1;
	}
	switch (test_alg & 0xff00) {
	case 0x0100:
		test_auth();
		break;
	case 0x0:
		test_cipher();
		break;
	default:

		break;
	}

	return 0;
}